package com.xsjiong.hoofen;

import android.content.Context;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import okhttp3.Request;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

public class IO {
	public static int BUFFER_SIZE = 1024;

	private static OkHttpClient Client;

	public static void Initialize(Context cx) {
		try {
			Client = new OkHttpClient.Builder()
					.connectTimeout(8000, TimeUnit.MILLISECONDS)
					.sslSocketFactory(new TLSSocketFactory(), new X509TrustManager() {
						@Override
						public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
						}

						@Override
						public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
						}

						@Override
						public X509Certificate[] getAcceptedIssuers() {
							return new X509Certificate[0];
						}
					})
					.cache(new Cache(cx.getCacheDir(), G.CACHE_SIZE))
					.build();
		} catch (Throwable t) {
			Logs.e("Error While Initializing OkHttp Client", t);
		}
	}

	public static class TLSSocketFactory extends SSLSocketFactory {
		private SSLSocketFactory O;

		public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
			SSLContext context = SSLContext.getInstance("TLS");
			context.init(null, null, null);
			O = context.getSocketFactory();
		}

		@Override
		public String[] getDefaultCipherSuites() {
			return O.getDefaultCipherSuites();
		}

		@Override
		public String[] getSupportedCipherSuites() {
			return O.getSupportedCipherSuites();
		}

		@Override
		public Socket createSocket() throws IOException {
			return enableTLSOnSocket(O.createSocket());
		}

		@Override
		public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
			return enableTLSOnSocket(O.createSocket(s, host, port, autoClose));
		}

		@Override
		public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
			return enableTLSOnSocket(O.createSocket(host, port));
		}

		@Override
		public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
			return enableTLSOnSocket(O.createSocket(host, port, localHost, localPort));
		}

		@Override
		public Socket createSocket(java.net.InetAddress host, int port) throws IOException {
			return enableTLSOnSocket(O.createSocket(host, port));
		}

		@Override
		public Socket createSocket(java.net.InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
			return enableTLSOnSocket(O.createSocket(address, port, localAddress, localPort));
		}

		private Socket enableTLSOnSocket(Socket socket) {
			if (socket != null && (socket instanceof SSLSocket))
				((SSLSocket) socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
			return socket;
		}
	}

	public static byte[] Read(InputStream in) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		Copy(in, out);
		out.close();
		return out.toByteArray();
	}

	public static boolean SafeDelete(File f) {
		if (f == null || (!f.exists())) return false;
		if (f.isFile()) return f.delete();
		File[] fs = f.listFiles();
		boolean ret = true;
		for (int i = 0; i < fs.length; i++) ret &= SafeDelete(fs[i]);
		return ret;
	}

	public static void Copy(InputStream in, OutputStream out) throws IOException {
		int read;
		byte[] buf = new byte[BUFFER_SIZE];
		while ((read = in.read(buf)) != -1) out.write(buf, 0, read);
		in.close();
	}

	public static String URLString(String url) throws IOException {
		return URLString(new URL(url));
	}

	public static String URLString(URL url) throws IOException {
		return Client.newCall(new Request.Builder().url(url).get().build()).execute().body().string();
	}

	public static byte[] URLBytes(String url) throws IOException {
		return URLBytes(new URL(url));
	}

	public static byte[] URLBytes(URL url) throws IOException {
		return Client.newCall(new Request.Builder().url(url).get().build()).execute().body().bytes();
	}

	public static InputStream URLByteStream(String url) throws IOException {
		return URLByteStream(new URL(url));
	}

	public static InputStream URLByteStream(URL url) throws IOException {
		return Client.newCall(new Request.Builder().url(url).get().build()).execute().body().byteStream();
	}

	public static void TransferURL(String url, OutputStream out) throws IOException {
		TransferURL(new URL(url), out);
	}

	public static void TransferURL(URL url, OutputStream out) throws IOException {
		Copy(Client.newCall(new Request.Builder().url(url).get().build()).execute().body().byteStream(), out);
	}
}
